#pragma once
#include "sstream.h"
using namespace std;

#define Tnline template<typename T> inline

class Property
{
public:
	string TYPE;
	string CHECK;
	sstream DEFAULT;
	bool UNIQUE;
	bool NOTNULL;
	bool PRIMARY;
	char ASC_DESC;
	bool AUTOINCREMENT;
public:
	inline Property(void)
	:UNIQUE(0)
	,PRIMARY(0)
	,NOTNULL(0)
	,ASC_DESC(0)
	,AUTOINCREMENT(0){}
};
class Define
{
public:
	Property propery;
public:
	inline Define&  define	(const string& s);
	inline Define&  check	(const string&);
	inline Define&  unique	(bool);
	inline Define&  primary	(bool);
	inline Define&  notnull	(bool);
	inline Define&  asc		(bool);
	inline Define&  desc	(bool);
	inline Define&  autoinc	(bool);
	inline Define&  dint	(void);
	inline Define&  dtext	(void);
	inline Define&  dfloat	(void);
	inline Define&  ddouble (void);
	Tnline Define&  ddefault(T v);
public:
	inline string data(void)const;
};
Tnline Define& Define::ddefault(T v)
{
	propery.DEFAULT.str("");
	propery.DEFAULT << " DEFAULT '" << v << "'";
	return *this;
}
inline Define& Define::check(const string& s)
{
	return *this;
}
inline Define& Define::unique(bool b=true)
{
	propery.UNIQUE = b;
	return *this;
}
inline Define& Define::primary(bool b=true)
{
	propery.PRIMARY = b;
	return *this;
}
inline Define& Define::notnull(bool b=true)
{
	propery.NOTNULL = b;
	return *this;
}
inline Define& Define::asc(bool b=true)
{
	propery.ASC_DESC = b ? 1 : 0;
	return *this;
}
inline Define& Define::desc(bool b=true)
{
	propery.ASC_DESC = b ? 2 : 0;
	return *this;
}
inline Define& Define::autoinc(bool b=true)
{
	propery.AUTOINCREMENT = b;
	return *this;
}
inline Define& Define::dint(void)
{
	propery.TYPE = " INT";
	return *this;
}
inline Define& Define::dtext(void)
{
	propery.TYPE = " TEXT";
	return *this;
}
inline Define& Define::dfloat(void)
{
	propery.TYPE = " FLOAT";
	return *this;
}
inline Define& Define::ddouble(void)
{
	propery.TYPE = " DOUBLE";
	return *this;
}

string Define::data(void)const
{
	return(propery.TYPE)
		+ (propery.CHECK)
		+ (propery.DEFAULT.str())
		+ (propery.UNIQUE  ? " UNIQUE" : "")
		+ (propery.NOTNULL ? " NOTNULL" : "")
		+ (propery.AUTOINCREMENT ? " AUTOINCREMENT" : "")
		+ (propery.PRIMARY ? " PRIMARY KEY" : "")
		+ (propery.PRIMARY && propery.ASC_DESC==1 ? " ASC" : "")
		+ (propery.PRIMARY && propery.ASC_DESC==2 ? " DESC" : "");
}

class DefineMap
{
public:
	map<string,Define> _define;
public:
	inline void clear(void);
	inline string data(void)const;
	inline Define& define(const string& s);
};
inline void DefineMap::clear(void)
{
	_define.clear();
}
inline string DefineMap::data(void)const
{
	string s;
	map<string,Define>::const_iterator i;
	for(i = _define.begin(); i != _define.end(); i++)
	{
		if(s.empty() == false)
		{
			s += ", ";
		}
		s += i->first + i->second.data();
	}
	return s;
}
inline Define& DefineMap::define(const string& s)
{
	return _define[s];
}

class Create
{
private:
	string    _table;
	DefineMap _define;
public:
	inline Create(const string&);
	inline string data(void)const;
	inline Create& clear(void);
	inline Define& define(const string&);
};

inline Create::Create(const string& s)
:_table(s)
{
}
inline Create& Create::clear(void)
{
	_define.clear();
	return *this;
}
inline string Create::data(void)const
{
	return "CREATE TABLE IF NOT EXISTS " +  _table +  " (" + _define.data() + ");";
}
inline Define& Create::define(const string& s)
{
	return _define.define(s);
}
#undef Tnline
